home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_n_z.arj / STROBE.ASM < prev    next >
Assembly Source File  |  1989-01-13  |  21KB  |  532 lines

  1.         page    ,132                    ; print in condensed mode
  2.  
  3.         title   STROBE - Monitor a memory field for changes  -  P. Quale 3/87
  4. cseg    segment para
  5.         assume  cs:cseg,ds:cseg,es:nothing,ss:nothing
  6.  
  7.                 org     2ch
  8. env_seg         dw      ?               ;pointer to our copy of environment
  9.                 org     80h             ;parm list starts here...
  10. parm_len        db      ?               ;its length
  11. parm_char       db      127 dup(?)      ;the parms
  12.         org     100h
  13. strobe  proc    near
  14. begin:
  15.         jmp     init                    ;go to once-only code
  16.  
  17. prog_id:db      'STROBE 1.02 '
  18.         db      'IBM Internal Use Only '
  19.         db      'P. Quale 03/87'
  20. id_end  equ     $
  21.  
  22. ;history:
  23. ;    1.01, 05/26/87: revised to incorporate changes suggested by Kevin McCarthy.
  24. ;       The addresses being monitored can now be patched on the fly by patching
  25. ;       new values into the fields intvect and intvect2, which have been
  26. ;       changed from EQU values to doubleword pointers.
  27.  
  28. ;    1.02, 01/13/89: STROBE now releases its memory when 'R'emoved.  Also
  29. ;       removed a potential BRS bug if a derivative program were to have an
  30. ;       ASSUME DS:CSEG directive in the timer interrupt routine, by changing
  31. ;       the exit statement from 'JMP OLDVECT' to 'JMP CS:OLDVECT'.
  32.  
  33. ;-------macro to simplify window repositioning
  34. posw    macro   name,row,column                 ;convert row/column location
  35. name    equ     ((row-1)*160)+((column-1)*2)    ;to position in video buffer
  36.         endm
  37.  
  38. ;-------macro to define field positions within the window
  39. posf    macro   name,row,column                 ;convert line/column location
  40. name    equ     corner1+((row-1)*160)+((column-1)*2)    ;to pos in video buffer
  41.         endm
  42.  
  43.         db      0               ;waste a byte to align patch area nicely
  44. old_vect        label   dword           ;original timer vector saved here
  45. old_ofs         dw      0               ;offset
  46. old_seg         dw      0               ;segment
  47. ;               keep old_vect as close to front of program as possible
  48.  
  49.         page
  50. ;-------entries on this page are grouped together to facilitate
  51. ;-------changes in window location or storage area(s) being tracked
  52.  
  53. ;-------next entries define the control block to be "watched"
  54. ;-------in this case, we watch to see when int 21 gets hooked
  55. intnum          equ     021h            ;interrupt number we care about
  56. intvect         dw      intnum*4,0      ;offset, segment (patchable)
  57. prev_value      dw      2 dup(?)        ;its previous (or initial) contents
  58.  
  59. ;-------any other memory fields of interest
  60. intnum2         equ     02fh            ;another interrupt number we care about
  61. intvect2        dw      intnum2*4,0     ;offset, segment (patchable)
  62.  
  63. ;-------next three entries define the window size and location
  64.         posw    corner1,1,62    ;upper left corner of window
  65.         posw    corner2,1,80    ;upper right corner
  66.         posw    corner4,5,80    ;lower right corner
  67.  
  68. ;-------next entries define location of each field within the window
  69.         posf    out1,1,1        ;moving blob goes here on line 1 of window
  70.         posf    out2,2,10       ;entry count here at line 2 col 10 of window
  71.         posf    out3,3,10       ;contents of major block being tracked
  72.         posf    out4,4,10       ;yet another block being tracked
  73.         posf    out5,5,10       ;cs:ip of routine running when timer went off
  74.  
  75. ;-------end of EQUs, etc. peculiar to a specific application of STROBE
  76.         page
  77.  
  78. ;-------next two equates are needed by the window-clearing code
  79. windwid equ     (corner2-corner1+2)/2           ;width in screen positions
  80. winddep equ     (corner4-corner2+160)/160       ;depth in lines
  81.  
  82. clknum  equ     08h             ;timer interrupt number
  83. clkvect equ     clknum*4        ;its vector address
  84.  
  85. ;-------window attributes/colors used to indicate a value change
  86. table_mono      db      20h,70h,28h,29h  ;normal, reversed, bright, underlined
  87. table_color     db      07h,04fh,2fh,5fh ;white on: black, red, green, magenta
  88. max_change      equ     3       ;n'color changes before we recycle (zero-based)
  89. change_index    dw      (max_change)     ;forces a start at first color
  90.  
  91. flags           db      0       ;flag bits...
  92. mono            equ     01h
  93. color           equ     02h
  94. sync            equ     04h
  95.  
  96. vidseg          dw      0       ;video segment address
  97. vidsegm         equ     0b000h  ;video segment address if mono
  98. vidsegc         equ     0b800h  ;video segment address if color
  99. attrib          db      0       ;screen attribute byte
  100. tick_count      dw      0       ;cyclic index into tick-display line
  101. max_tick        equ     18      ;limit for tick_count
  102. blob            equ     0feh    ;timer-tick char. feh=small square, dbh=big one
  103. entry_count     dw      0       ;count of timer-tick entries to this program
  104. count_carry     db      0       ;how many times entry_count wrapped
  105. ss_save         dw      0       ;ss saved here upon entry
  106. sp_save         dw      0       ;sp saved here
  107.  
  108. ;-------enter here on timer interrupt
  109. timer_int:
  110.         assume  cs:cseg,ds:nothing,es:nothing,ss:nothing
  111.         pushf                   ;preserve flags
  112.  
  113. ;-------switch to our own stack
  114.         cli                     ;disable interrupts (and keep them that way)
  115.         mov     ss_save,ss
  116.         mov     sp_save,sp
  117.         push    cs
  118.         pop     ss
  119.         lea     sp,stack_end
  120.         nop
  121.  
  122. ;-------save the rest of the registers
  123.         push    ax
  124.         push    bx
  125.         push    cx
  126.         push    dx
  127.         push    bp
  128.         push    di
  129.         push    si
  130.         push    ds
  131.         push    es
  132.  
  133. ;-------set ds for our internal variables, es for video buffer
  134.         push    cs
  135.         pop     ds
  136.         assume  ds:cseg
  137.         push    vidseg          ;set video segment address
  138.         pop     es              ;...
  139.  
  140. ;-------make sure our stack size hasn't been exceeded
  141. ;       (for testing; probably an unnecessary check now)
  142.         mov     ax,0fefeh               ;string that must still be there
  143.         cmp     ax,stack_bottom         ;has anyone overrun our stack?
  144.         je      check_major             ;no
  145. tight_loop:                             ;yes, so stop right here and now
  146.         mov     ax,05341h               ;but leave tracks
  147.         mov     es:corner1,ax           ;upper left corner of window
  148.         jmp     short tight_loop
  149.  
  150. check_major:
  151. ;-------check to see if value of memory field we're watching has changed:
  152.         push    ds              ;save ds for a moment
  153.         assume  ds:nothing
  154.         lds     bx,dword ptr intvect    ;load dword pointer
  155.         mov     ax,ds:[bx]      ;pick up first 2 bytes of field
  156.         mov     bx,ds:[bx+2]    ;next 2 bytes
  157.         pop     ds
  158.         assume  ds:cseg
  159.         cmp     ax,prev_value   ;still the same?
  160.         jne     has_changed     ;no
  161.         cmp     bx,prev_value+2 ;still the same?
  162.         je      clear_window    ;yes
  163. has_changed:                    ;new value.  save new field value and
  164.         call    save_major      ;alert user by changing window background color
  165.  
  166. clear_window:
  167. ;-------clear the screen window and set the background color
  168.         mov     al,20h                  ;get a blank
  169.         mov     ah,byte ptr attrib      ;pick up window color byte
  170.         mov     di,corner1      ;where to start clearing
  171.         mov     cx,winddep      ;n'lines in window
  172.         call    sync_cga        ;avoid flicker during writes if CGA display
  173. clrline:
  174.         push    cx              ;save line count
  175.         mov     cx,windwid      ;width of window
  176. clrbyte:
  177.         mov     word ptr es:0[di],ax    ;clear one screen position
  178.         inc     di
  179.         inc     di
  180.         loop    clrbyte         ;loop for all positions this line
  181.         add     di,160-(windwid*2)      ;point to next line of window
  182.         pop     cx              ;all window lines cleared?
  183.         loop    clrline         ;no
  184.  
  185. ;-------move blob from left to right on top line to indicate timer-tick rate
  186. show_blob:
  187.         mov     bx,tick_count   ;blob's next position on the line
  188.         mov     byte ptr es:out1[bx],blob       ;get timer-tick character
  189.         inc     bx
  190.         inc     bx              ;compensate for double spacing in video buffer
  191.         cmp     bx,max_tick*2   ;have we reached the extreme right?
  192.         jna     same_cycle      ;not yet
  193.         xor     bx,bx           ;yes, restart blob at leftmost position
  194. same_cycle:
  195.         mov     tick_count,bx
  196.  
  197. ;-------for the curious, display count of entries to this routine
  198. show_count:
  199.         mov     ax,entry_count
  200.         inc     ax
  201.         jnz     no_overflow
  202.         inc     byte ptr count_carry
  203. no_overflow:
  204.         mov     entry_count,ax
  205.  
  206.         mov     di,out2
  207.         mov     ah,byte ptr count_carry
  208.         call    cvtbh
  209.         call    putchar
  210.         mov     ah,byte ptr entry_count+1
  211.         call    cvtbh
  212.         call    putchar
  213.         mov     ah,byte ptr entry_count
  214.         call    cvtbh
  215.         call    putchar
  216.  
  217. ;-------get address of routine interrupted when timer went off
  218. ;-------by pointing into entry-time stack for its cs:ip
  219.         push    ss_save
  220.         push    sp_save
  221.         pop     si
  222.         pop     ds
  223.         assume  ds:nothing
  224.         add     si,2            ;point to saved cs:ip in stack
  225.         mov     di,out5         ;where to display it
  226.         call    disp_addr
  227.  
  228. ;-------display the control block of major interest
  229. show_major:
  230.         mov     ax,intvect+2
  231.         mov     ds,ax           ;set ds to segment to display
  232.         mov     si,intvect      ;offset to display
  233.         mov     di,out3         ;where to display it
  234.         call    disp_addr
  235.  
  236. ;-------display any control blocks of secondary interest here...
  237. show_minor:
  238.         mov     ax,intvect2+2
  239.         mov     ds,ax           ;set ds to segment to display
  240.         mov     si,intvect2     ;offset to display
  241.         mov     di,out4         ;where to display it
  242.         call    disp_addr
  243.  
  244. ;-------done.  restore the registers
  245.         pop     es
  246.         pop     ds
  247.         pop     si
  248.         pop     di
  249.         pop     bp
  250.         pop     dx
  251.         pop     cx
  252.         pop     bx
  253.         pop     ax
  254.         cli                     ;no interrupts during upcoming stack-switch
  255.         mov     ss,cs:ss_save
  256.         mov     sp,cs:sp_save
  257.         popf
  258.         jmp     cs:old_vect     ;pass control to the routine we unhooked
  259.  
  260. ;-------subroutines...
  261.  
  262. ;-------handle a change to the value of the field we're watching:
  263. ;-------1) save the new value
  264. ;-------2) switch to the next color
  265. save_major      proc    near
  266.         push    ax
  267.         push    bx
  268.         push    ds
  269.         assume  ds:nothing
  270.         lds     bx,dword ptr intvect    ;load dword pointer into ds:bx
  271.         mov     ax,ds:[bx]      ;first 2 bytes to save
  272.         mov     bx,ds:[bx+2]    ;next 2 bytes
  273.         pop     ds
  274.         assume  ds:cseg
  275.         mov     prev_value,ax   ;save new value
  276.         mov     prev_value+2,bx ;...
  277.  
  278. next_color:                     ;switch to the next background color
  279.         lea     bx,table_mono   ;assume mono screen
  280.         test    flags,mono      ;is it?
  281.         jnz     test_max        ;yup
  282.         lea     bx,table_color
  283. test_max:
  284.         mov     ax,change_index
  285.         inc     ax
  286.         cmp     ax,max_change   ;have we used up all the colors yet?
  287.         jng     get_next_attrib ;no
  288.         xor     ax,ax           ;yes, restart with the first
  289. get_next_attrib:
  290.         add     bx,ax           ;point to new attribute char
  291.         mov     bl,ds:0[bx]     ;pick it up
  292.         mov     attrib,bl       ;stash it for others to find
  293.         mov     change_index,ax ;save index for next time
  294.         pop     bx
  295.         pop     ax
  296.         ret
  297. save_major      endp
  298.  
  299. ;-------if using a CGA display, synchronize to avoid flicker
  300. sync_cga        proc    near
  301.         test    cs:flags,sync   ;did user tell us we're on a CGA?
  302.         jz      sync_ret        ;no, just return to caller
  303.         push    ax
  304.         push    dx
  305.         mov     dx,03dah        ;CGA status register
  306. ;-------the first 4 lines of code below seemed like a good idea,
  307. ;-------but the CGA flicker goes away without them (on an 8MHz AT),
  308. ;-------so they're commented out.
  309. ;ync_loop_1:
  310. ;;;;;;;;in      al,dx           ;wait until outside of vertical sync pulse
  311. ;;;;;;;;test    al,08h
  312. ;;;;;;;;jnz     sync_loop_1
  313. sync_loop_2:
  314.         in      al,dx           ;now wait for start of new sync pulse
  315.         test    al,08h
  316.         jz      sync_loop_2
  317.         pop     dx
  318.         pop     ax
  319. sync_ret:
  320.         ret
  321. sync_cga        endp
  322.  
  323. ;-------display an address in seg:offset form
  324. ;               ds:si points to the address to display
  325. ;               es:di is where in the video buffer to put the result
  326. disp_addr       proc    near
  327.         mov     ah,byte ptr ds:3[si]    ;segment
  328.         call    cvtbh
  329.         call    putchar
  330.         mov     ah,byte ptr ds:2[si]
  331.         call    cvtbh
  332.         call    putchar
  333.  
  334.         mov     byte ptr es:[di],':'    ;semicolon
  335.  
  336.         add     di,2
  337.         mov     ah,byte ptr ds:1[si]    ;offset
  338.         call    cvtbh
  339.         call    putchar
  340.  
  341.         mov     ah,byte ptr ds:0[si]
  342.         call    cvtbh
  343.         call    putchar
  344.         ret
  345. disp_addr       endp
  346.  
  347. ;-------convert the byte in ah to ascii hex and pass result back in ax
  348. hextabl db      '0123456789ABCDEF'      ;the hex alphabet
  349. cvtbh   proc    near
  350.         push    bx              ;save
  351.         mov     al,ah           ;duplicate the argument byte
  352.         shr     ah,1            ;shift left nybble over by 4
  353.         shr     ah,1            ; ...
  354.         shr     ah,1            ; ...
  355.         shr     ah,1            ; ...
  356.         and     ax,0f0fh        ;yields two indices into hex table
  357.         xor     bx,bx           ;get a zero
  358.         mov     bl,ah                   ;index value for left nybble
  359.         mov     ah,cs:hextabl[bx]       ;pick up corresponding table char
  360.         mov     bl,al                   ;index for right nybble
  361.         mov     al,cs:hextabl[bx]       ;pick up table char
  362.         pop     bx              ;restore
  363.         ret                     ;return with the answer in ax
  364. cvtbh   endp
  365.  
  366. ;-------put a pair of ascii hex digits into video buffer
  367. putchar proc    near
  368.         mov     es:0[di],ah
  369.         mov     es:2[di],al
  370.         add     di,4            ;bump index as a convenience to caller
  371.         ret
  372. putchar endp
  373.  
  374. stack_bottom    dw      0fefeh          ;stack underrun sentinel
  375. stack   db      50  dup('STACK ')       ;our own stack, probably too big
  376. resident_paras  equ     ($-1-cseg)/16           ;padding to bring us to...
  377.                 org     (resident_paras+1)*16   ;next doubleword boundary
  378. stack_end       equ     $                       ;end of resident code
  379.  
  380.  
  381.         page
  382. ;-------begin one-time initialization code...
  383. init:
  384.         assume  cs:cseg,ds:cseg,es:cseg,ss:cseg
  385.  
  386. ;-------see if any parms given:
  387.                                 ;  M   use Monochrome display
  388.                                 ;  C   use Color display
  389.                                 ;  S   Synchronize to avoid CGA flicker
  390.                                 ;  R   Remove (unhook) an active copy of STROBE
  391.  
  392.         mov     ah,'R'          ;look for 'R'emove
  393.         call    parmchk
  394.         jne     chk_parm_2      ;not found
  395.         jmp     remove
  396.  
  397. chk_parm_2:
  398.         mov     ah,'M'          ;look for 'M'ono
  399.         call    parmchk
  400.         je      setup_mono      ;found
  401.  
  402.         mov     ah,'S'          ;look for 'S'ync
  403.         call    parmchk
  404.         jne     chk_parm_3      ;not found
  405.         or      flags,sync
  406.  
  407. chk_parm_3:
  408.         mov     ah,'C'          ;look for 'C'olor
  409.         call    parmchk
  410.         je      setup_color     ;found
  411.  
  412. ;-------no user screen-choice, so default to the active screen
  413.         int     011h            ;ask BIOS what equipment we have
  414.         and     al,not 030h     ;isolate screen bits
  415.         cmp     al,030h         ;video mode = mono?
  416.         jne     setup_color     ;no
  417.  
  418. setup_mono:
  419.         or      flags,mono      ;set up for monochrome display
  420.         mov     vidseg,vidsegm  ;...
  421.         jmp     short finish
  422.  
  423. setup_color:
  424.         or      flags,color     ;set up for color display
  425.         mov     vidseg,vidsegc  ;...
  426.  
  427. finish:
  428. ;-------release our copy of the environment
  429.         push    es              ;save es
  430.         mov     ax,env_seg      ;point es to our copy of the environment
  431.         mov     es,ax           ;...
  432.         mov     ah,49h          ;subfunction = free allocated memory
  433.         int     21h             ;do it
  434.         pop     es              ;restore es
  435.  
  436.         call    save_major      ;save comparand & set up initial window color
  437.  
  438. ;-------save current interrupt 08 vector; set up to intercept its interrupts.
  439. ;-------note that although a copy of us may already be resident, we don't care:
  440. ;-------the copy will get a turn to do its stuff (hopefully in another window)
  441.         xor     ax,ax           ;get a zero
  442.         mov     ds,ax           ;point ds to interrupt vectors
  443.         assume  ds:nothing
  444.         cli                     ;no interrupts just now
  445.  
  446.         mov     di,ds:clkvect   ;pick up offset that's there now
  447.         mov     es:old_ofs,di   ;stash it
  448.         lea     ax,timer_int    ;our own interrupt handler offset
  449.         mov     ds:clkvect,ax   ;replace the old offset
  450.  
  451.         mov     ax,ds:clkvect+2 ;pick up segment that's there now
  452.         mov     es:old_seg,ax   ;stash it
  453.         mov     ds:clkvect+2,cs ;replace the old segment address
  454.  
  455.         sti                     ;enable interrupts again
  456.  
  457. ;-------terminate and stay resident
  458.         lea     dx,stack_end    ;get size of resident portion
  459.         shr     dx,1            ;convert to paragraphs
  460.         shr     dx,1
  461.         shr     dx,1
  462.         shr     dx,1
  463.         mov     ah,31h          ;subfunction = tsr
  464.         xor     al,al           ;exit code = zero
  465.         int     21h             ;exit
  466.  
  467. ;-------remove an active copy of ourself by restoring
  468. ;-------its saved interrupt vector and freeing its memory
  469. msg_not_hooked  db      'No active copy of STROBE was found',0dh,0ah,'$'
  470. remove:
  471. ;-------we can only do this if interrupt 08 vector points to a copy of us
  472.         xor     ax,ax
  473.         mov     es,ax
  474.         assume  es:nothing
  475.  
  476.         mov     ax,es:clkvect+2 ;ax = cs of interrupt handler
  477.         mov     es,ax           ;point es to potential copy of us
  478.         lea     si,prog_id      ;point to our program id and version
  479.         mov     di,si
  480.         mov     cx,id_end-prog_id       ;number of bytes that must match
  481.         cld                     ;left-to-right, please
  482. rep     cmpsb                   ;is it a copy of us?
  483.         jne     nocando         ;no
  484.         xor     ax,ax           ;yes, unhook it from interrupt 08 chain
  485.         mov     ds,ax
  486.         assume  ds:nothing
  487.         cli
  488.         mov     ax,es:old_seg   ;restore interrupt vector the copy of us saved
  489.         mov     ds:clkvect+2,ax
  490.         mov     ax,es:old_ofs
  491.         mov     ds:clkvect,ax
  492.         sti
  493. ;-------release memory occupied by copy we just unhooked
  494.         mov     ah,49h          ;subfunction = free allocated memory
  495.         int     21h             ;do it (es still points to the copy)
  496.         jmp     short exit_remove       ;all done.
  497. nocando:
  498.         lea     dx,msg_not_hooked
  499.         push    cs              ;be sure we have a good ds
  500.         pop     ds              ;...
  501.         mov     ah,09h          ;subfunction = output to display
  502.         int     21h             ;display the msg
  503. exit_remove:
  504.         ret                     ;exit program
  505.  
  506. ;-------subroutines...
  507.  
  508. ;-------search for a user parm matching the character in ah
  509. parmchk proc    near
  510.         xor     ch,ch
  511.         mov     cl,parm_len     ;length of parm list
  512.         jcxz    not_found
  513.         mov     al,ah           ;duplicate the argument
  514.         add     al,020h         ;lowercase it
  515.         xor     bx,bx           ;set search index to zero
  516. next_char:
  517.         cmp     al,parm_char[bx]
  518.         je      was_found       ;match; exit leaving zf = on
  519.         cmp     ah,parm_char[bx]
  520.         je      was_found       ;match; exit leaving zf = on
  521.         inc     bx
  522.         loop    next_char
  523. not_found:
  524.         cmp     ah,al           ;set zf = off
  525. was_found:
  526.         ret
  527. parmchk endp
  528.  
  529. strobe  endp
  530. cseg    ends
  531.         end     begin
  532.